﻿using System.Collections.Generic;
using UvsChess;

namespace StudentAI
{
    public class MoveGenerator2
    {

        public List<ChessMove> GenerateMoves(ChessBoard board, int x, int y, ChessColor color)
        {
            List<ChessMove> moves = null;
            switch (board[x,y])
            {
                    case ChessPiece.WhitePawn:
                    case ChessPiece.BlackPawn:
                    moves = PawnMoves(board,x,y,color);
                    break;
                    case ChessPiece.WhiteRook:
                    case ChessPiece.BlackRook:
                    moves = RookMoves(board, x, y, color);
                    break;
                    case ChessPiece.WhiteQueen:
                    case ChessPiece.BlackQueen:
                    moves = QueenMoves(board, x, y, color);
                    break;
                    case ChessPiece.WhiteBishop:
                    case ChessPiece.BlackBishop:
                    moves = BishopMoves(board, x, y, color);
                    break;
                    case ChessPiece.WhiteKnight:
                    case ChessPiece.BlackKnight:
                    moves = KnightMoves(board, x, y, color);
                    break;
                    case ChessPiece.WhiteKing:
                    case ChessPiece.BlackKing:
                    moves = KingMoves(board, x, y, color);
                    break;
            }
            return moves;
        }

        private List<ChessMove> PawnMoves(ChessBoard board, int x, int y, ChessColor color)
        {
            List<ChessMove> Moves = new List<ChessMove>();
            ChessFlag flag = ChessFlag.NoFlag;
            if (color == ChessColor.White)
            {
                if (y - 1 >= 0 && board[x, y - 1] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x, y - 1)));
                }
                if (y - 1 >= 0 && x - 1 >= 0 && board[x - 1, y - 1] < ChessPiece.Empty)
                {
                    if (board[x - 1, y - 1] == ChessPiece.BlackKing)
                    {
                        flag = ChessFlag.Check;
                    }
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x - 1, y - 1),flag));
                }
                if (y - 1 < ChessBoard.NumberOfColumns && x + 1 < ChessBoard.NumberOfRows && board[x + 1, y - 1] < ChessPiece.Empty)
                {
                    if (board[x + 1, y - 1] == ChessPiece.BlackKing)
                    {
                        flag = ChessFlag.Check;
                    }
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x + 1, y - 1),flag));
                }
                if (y == 6 && board[x, y - 1] == ChessPiece.Empty && board[x, y - 2] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x, y - 2)));
                }
            }
            else
            {
                if (y + 1 < ChessBoard.NumberOfRows && board[x, y + 1] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x, y + 1)));
                }
                if (y + 1 < ChessBoard.NumberOfRows && x + 1 < ChessBoard.NumberOfColumns && board[x + 1, y + 1] > ChessPiece.Empty)
                {
                    if (board[x + 1, y + 1] == ChessPiece.WhiteKing)
                    {
                        flag = ChessFlag.Check;
                    }
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x + 1, y + 1),flag));
                }
                if (y + 1 < ChessBoard.NumberOfColumns && x - 1 >= 0 && board[x - 1, y + 1] > ChessPiece.Empty)
                {
                    if (board[x - 1, y + 1] == ChessPiece.WhiteKing)
                    {
                        flag = ChessFlag.Check;
                    }
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x - 1, y + 1),flag));
                }
                if (y == 1 && board[x, y + 1] == ChessPiece.Empty && board[x, y + 2] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x, y + 2)));
                }
            }
            return Moves;
        }

        private List<ChessMove> RookMoves(ChessBoard board, int x, int y, ChessColor color)
        {
            List<ChessMove> Moves = new List<ChessMove>();
            ChessColor killColor = ChessColor.White;
            if (color == ChessColor.White)
            {
                killColor = ChessColor.Black;
            }

            for (int i = y + 1; i < ChessBoard.NumberOfRows; i++) // direction down
            {
                if (board[x, i] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x, i)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, x, i, killColor);
                    if(move != null)
                    {
                        Moves.Add(move);
                    }
                    
                    break;
                }

            }
            for (int i = y - 1; i >= 0; i--) // direction up
            {
                if (board[x, i] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(x, i)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, x, i, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                    break;
                }

            }
            for (int j = x - 1; j >= 0; j--) // direction left
            {
                if (board[j, y] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(j, y)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, j, y, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                   
                    break;
                }

            }
            for (int j = x + 1; j < ChessBoard.NumberOfColumns; j++) // direction right
            {
                if (board[j, y] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(j, y)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, j, y, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                    break;
                }

            }
            return Moves;
        }

        private List<ChessMove> KnightMoves(ChessBoard board, int x, int y, ChessColor color)
        {
            List<ChessMove> Moves = new List<ChessMove>();
            ChessColor killColor = ChessColor.White;
            if (color == ChessColor.White)
            {
                killColor = ChessColor.Black;
            }
            int x1 = x - 1;
            int y1 = y - 2;
            //up left direction
            if ((x1 >= 0 && y1 >= 0))
            {
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
                
            }
            // up right direction
            x1 = x + 1;
            if ((x1 < ChessBoard.NumberOfColumns && y1 >= 0))
            {
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
            }
            // right up direction
            y1 = y - 1;
            x1 = x + 2;
            if (x1 < ChessBoard.NumberOfColumns && y1 >= 0)
            {
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
            }
            // right down direction
            y1 = y + 1;
            if (x1 < ChessBoard.NumberOfRows && y1 < ChessBoard.NumberOfColumns)
            {
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
            }
            // down left direction
            x1 = x - 1;
            y1 = y + 2;
            if (x1 >= 0 && y1 < ChessBoard.NumberOfRows)
            {
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
            }
            //down right direction
            x1 = x + 1;
            if (x1 < ChessBoard.NumberOfRows && y1 < ChessBoard.NumberOfColumns)
            {
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
            }
            // left up direction
            x1 = x - 2;
            y1 = y - 1;
            if (x1 >= 0 && y1 >= 0)
            {
                
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
            }
            // left down direction
            y1 = y + 1;
            if (x1 >= 0 && y1 < ChessBoard.NumberOfColumns)
            {
                var move = SpotAvailable(board, x, y, x1, y1, killColor);
                if (move != null)
                {
                    Moves.Add(move);
                }
            }
            return Moves;

        }

        private ChessMove SpotAvailable(ChessBoard board, int oX, int oY, int x, int y, ChessColor killColor)
        {
             ChessMove move = null;
             if ((board[x, y] > ChessPiece.Empty && killColor == ChessColor.White) || (board[x, y] < ChessPiece.Empty && killColor == ChessColor.Black) || board[x, y] == ChessPiece.Empty)
             {
                 ChessFlag flag = ChessFlag.NoFlag;
                 if(board[x,y] == ChessPiece.BlackKing || board[x,y] == ChessPiece.WhiteKing)
                 {
                     flag = ChessFlag.Check;
                 }
                 move = new ChessMove(new ChessLocation(oX,oY),new ChessLocation(x,y), flag );
             }
            return move;
        }

        private List<ChessMove> BishopMoves(ChessBoard board, int x, int y, ChessColor color)
        {
            List<ChessMove> Moves = new List<ChessMove>();
            ChessColor killColor = ChessColor.White;
            if (color == ChessColor.White)
            {
                killColor = ChessColor.Black;
            }
            int i = x - 1;
            int j = y - 1;
            while (i >= 0 && j >= 0) // up left direction
            {
                if (board[i, j] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(i, j)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, i, j, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                    break;
                }
                i--;
                j--;
            }
            i = x + 1;
            j = y - 1;
            while (i < ChessBoard.NumberOfColumns && j >= 0) // up right direction
            {
                if (board[i, j] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(i, j)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, i, j, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                    break;
                }
                i++;
                j--;
            }
            i = x - 1;
            j = y + 1;
            while (i >= 0 && j < ChessBoard.NumberOfRows) // down left direction
            {
                if (board[i, j] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(i, j)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, i, j, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                    break;
                }
                i--;
                j++;
            }
            i = x + 1;
            j = y + 1;
            while (i < ChessBoard.NumberOfRows && j < ChessBoard.NumberOfColumns) // down right direction
            {
                if (board[i, j] == ChessPiece.Empty)
                {
                    Moves.Add(new ChessMove(new ChessLocation(x, y), new ChessLocation(i, j)));
                }
                else
                {
                    var move = SpotAvailable(board, x, y, i, j, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                    break;
                }
                i++;
                j++;
            }
            return Moves;
        }

        private List<ChessMove> QueenMoves(ChessBoard board, int x, int y, ChessColor color)
        {
            var moves = RookMoves(board, x, y, color);
            moves.AddRange(BishopMoves(board, x, y, color));
            return moves;
        }

        private List<ChessMove> KingMoves(ChessBoard board, int x, int y, ChessColor color)
        {
            List<ChessMove> Moves = new List<ChessMove>();
            ChessColor killColor = ChessColor.White;
            if (color == ChessColor.White)
            {
                killColor = ChessColor.Black;
            }
          
                //king moves up
                if (y - 1 >= 0 )
                {
                    var move = SpotAvailable(board, x, y, x, y - 1, killColor);
                    if(move != null)
                    {
                        Moves.Add(move);
                    }
                }
                // king moves up and left
                if (y - 1 >= 0 && x - 1 >= 0)
                {
                    var move = SpotAvailable(board, x, y, x - 1, y - 1, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                    
                }
                // king moves up and right
                if (y - 1 >= 0 && x + 1 < ChessBoard.NumberOfColumns )
                {
                    var move = SpotAvailable(board, x, y, x + 1, y - 1, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                }
                //king right moves
                if (x + 1 < ChessBoard.NumberOfColumns)
                {
                    var move = SpotAvailable(board, x, y, x + 1, y, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                }
                //king moves left
                if (x - 1 >= 0 )
                {
                    var move = SpotAvailable(board, x, y, x - 1, y, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                }
                //king moves down and left
                if (y + 1 < ChessBoard.NumberOfRows && x - 1 >= 0)
                {
                    var move = SpotAvailable(board, x, y, x - 1, y + 1, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                }
                //king moves down
                if (y + 1 < ChessBoard.NumberOfRows)
                {
                    var move = SpotAvailable(board, x, y, x, y + 1, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                }
                //king moves down and right
                if (y + 1 < ChessBoard.NumberOfColumns && x + 1 < ChessBoard.NumberOfRows )
                {
                    var move = SpotAvailable(board, x, y, x + 1, y + 1, killColor);
                    if (move != null)
                    {
                        Moves.Add(move);
                    }
                }
         
            return Moves;
        }
    }
}
